#include "BaseSolver.h"

#include <list>
#include <thread>
#include <chrono>
#include <iomanip>
#include <fstream>
#include <iostream>
#include <algorithm>
#include "DumpLog.h"
namespace Solver
{

BaseSolver::BaseSolver(SolverType_E type, const std::string &name):
    id_(0), printNum_(1), costTime_(0), type_(type), 
    name_(name), resFile_(""), 
    fun_(nullptr), bestVar_(nullptr), 
    resetParam_(std::make_shared<ResetParam_t>()),
    rd_(), gen_(rd_()), randNorm01_{0.5, 0.2168}, randUniform01_{0,1}
{

}

BaseSolver::~BaseSolver()
{

}

void BaseSolver::setID(uint32_t id)
{
    id_ = id;
}

uint32_t BaseSolver::getID() const
{
    return id_;
}

uint32_t BaseSolver::getCostTime() const
{
    return costTime_;
}

SolverType_E BaseSolver::getType() const
{
    return type_;
}

void BaseSolver::setPrintNum(uint32_t num)
{
    printNum_ = num;
}

void BaseSolver::setResetParam(uint32_t num, value_t r)
{
    resetParam_->limitIterNum = num;
    resetParam_->limitR       = std::fabs(r);
    if (resetParam_->limitR > 0.9)
    {
        resetParam_->limitR = 0.9;
    }
}

const std::string &BaseSolver::getName() const
{
    return name_;
}

void BaseSolver::setSaveResultFile(const std::string &f)
{
    resFile_ = f;
}

void BaseSolver::setFun(const std::shared_ptr<BaseFun> &fun)
{
    fun_ = fun;
}

bool BaseSolver::setVarRange(const VectorXd_t &a, const VectorXd_t &b)
{
    //1.
    if (a.size() == 0 || a.size() != b.size())
    {
        LogError("维度有误");
        return false;
    }

    //2.
    const std::size_t num = a.size();
    vecMin_.resize(num);
    vecMax_.resize(num);
    for (std::size_t i = 0; i != num; ++i)
    {
        if (a[i] < b[i])
        {
            vecMin_[i] = a[i];
            vecMax_[i] = b[i];
        }
        else
        {
            vecMin_[i] = b[i];
            vecMax_[i] = a[i];
        }
    }

    //3.
    return true;
}

bool BaseSolver::setVarRange(value_t a, value_t b, uint32_t dim)
{
    //1.
    if (dim == 0)
    {
        LogError("变量维度不能为0");
        return false;
    }

    //2.
    if (a > b)
    {
        return setVarRange(b, a, dim);
    }

    //3.
    vecMax_.resize(dim);
    vecMin_.resize(dim);
    std::fill(vecMin_.begin(), vecMin_.end(), a);
    std::fill(vecMax_.begin(), vecMax_.end(), b);
    return true;
}

void BaseSolver::stop()
{
    condition_.stop.store(true);
}

bool BaseSolver::solve(uint32_t popNum)
{
    //1.
    if (condition_.run.load())
    {
        LogWarn("当前求解器还在运行");
        return false;
    }

    //2.
    condition_.run.store(true);
    condition_.stop.store(false);
    costTime_  = 0;
    startTime_ = std::chrono::high_resolution_clock::now();

    //3.
    if (!initPop(popNum))
    {
        condition_.run.store(false);
        return false;
    }

    //3.
    if (!initSolver())
    {
        condition_.run.store(false);
        return false;
    }

    //4.
    vecHistoryY_.clear();
    condition_.currentInter = 0;
    condition_.currentError = std::numeric_limits<value_t>::max();
    return continueSolveCall(false);
}

bool BaseSolver::continueSolve()
{
    costTime_  = 0;
    startTime_ = std::chrono::high_resolution_clock::now();
    return continueSolveCall(true);
}

Condition_t &BaseSolver::getCondition()
{
    return condition_;
}

void BaseSolver::waitExit() const
{
    while (condition_.run.load())
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(64));
    }
}

const vecValue_t &BaseSolver::getHistory() const
{
    return vecHistoryY_;
}

std::shared_ptr<DataValue_t> BaseSolver::getResult() const
{
    return bestVar_ != nullptr ? bestVar_->best : nullptr;
}

void BaseSolver::waitAllSolverExit(const vecBaseSolver_t &solvers)
{
    //1.
    std::list<std::shared_ptr<BaseSolver>> listSolver;
    for (auto &solver : solvers)
    {
        listSolver.push_back(solver);
    }

    //2.
    while (listSolver.size())
    {
        //2.1
        std::this_thread::sleep_for(std::chrono::milliseconds(64));

        //2.2
        for (auto it = listSolver.begin(); it != listSolver.end();)
        {
            if ((*it)->getCondition().run.load())
            {
                ++it;
            }
            else
            {
                it = listSolver.erase(it);
            }
        }
    }
}

void waitSolverExit(std::list<std::shared_ptr<BaseSolver>> &listSolver, std::size_t num)
{
    while (listSolver.size() > num)
    {
        //1
        std::this_thread::sleep_for(std::chrono::milliseconds(64));

        //2.
        for (auto it = listSolver.begin(); it != listSolver.end();)
        {
            if ((*it)->getCondition().run.load())
            {
                ++it;
            }
            else
            {
                it = listSolver.erase(it);
            }
        }
    }
}

bool BaseSolver::init()
{
    return true;
}

bool BaseSolver::tryToResetInitValue()
{
    //1.
    if (resetParam_->limitIterNum == 0)
    {
        return false;
    }

    //2.
    if (bestVar_->best->y < resetParam_->upY)
    {
        resetParam_->iterNum = 0;
        if (bestVar_->best->y > 0.01)
        {
            resetParam_->upY = bestVar_->best->y * (1 - resetParam_->limitR);
            return false;
        }
        else if(bestVar_->best->y < -0.01)
        {
            resetParam_->upY = bestVar_->best->y * (1 + resetParam_->limitR);
            return false;
        }
        else if(bestVar_->best->y < 0)
        {
            resetParam_->upY = -0.011;
            return false;
        }
        else
        {
            return false;
        }
    }

    //3.
    ++resetParam_->iterNum;
    if (resetParam_->iterNum != resetParam_->limitIterNum)
    {
        return false;
    }

    //4.
    resetParam_->iterNum = 0;
    for (auto &var : vecVariable_)
    {
        if (var != bestVar_)
        {
            resetVar(var);
        }
    }
    
    return true;
}

bool BaseSolver::continueSolveCall(bool continueFlag)
{
    if (continueFlag)
    {
        //1.
        if (condition_.run.load())
        {
            return true;
        }

        //2.
        condition_.run.store(true);
        condition_.stop.store(false);
    }

    //3.
    std::thread th(&BaseSolver::run, this);
    th.detach();

    return true;
}

void BaseSolver::run()
{
    //1.
    uint32_t printNum(0);
    updateBestVar();
    vecHistoryY_.push_back(bestVar_->best->y);
    resetParam_->iterNum = 0;
    resetParam_->upY     = bestVar_->best->y * 8 + 10.0;
    for (;condition_.currentInter != condition_.limitIter && !condition_.stop.load() && condition_.currentError > condition_.limitError;)
    {
        //1.1
        tryToResetInitValue();

        //1.2
        solveByIter();

        //1.3
        updateBestVar();

        //1.4
        addInter();

        //1.5
        vecHistoryY_.push_back(bestVar_->best->y);

        //1.6
        ++condition_.currentInter;

        //1.7
        if (printNum_ == 0)
        {
            continue;
        }

        //1.8
        ++printNum;
        if (printNum == printNum_)
        {
            printNum = 0;
            LogInfo("迭代次数:{}, 当前最小值:{}", condition_.currentInter , condition_.currentError.load());
        }
    }

    //2.
    if (printNum_ && printNum)
    {
        LogInfo("迭代次数:{}, 当前最小值:{}", condition_.currentInter , condition_.currentError.load());
    }

    //3.
    saveResult();

    //4.
    costTime_ = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - startTime_).count() / 1000;
    condition_.run.store(false);
}

bool BaseSolver::initPop(uint32_t popNum)
{
    //1.
    if (popNum < 3)
    {
        LogError("种群数不能少于3");
        return false;
    }
    else if(vecMin_.size() == 0)
    {
        LogError("没有设置变量范围");
        return false;
    }
    else if(fun_ == nullptr)
    {
        LogError("没有设置最小化目标函数");
        return false;
    }

    //2.
    if (popNum > 10000)
    {
        popNum = 10000;
    }

    //3.
    Eigen::Index startIndex(0);
    const Eigen::Index num = vecMin_.size();
    vecVariable_.clear();
    if (bestVar_ != nullptr)
    {
        if (bestVar_->best->x.size() == num)
        {
            startIndex   = 1;
            bestVar_->id = 0;
            vecVariable_.push_back(bestVar_);
        }
    }

    //4.
    while (vecVariable_.size() != popNum)
    {
        vecVariable_.push_back(std::make_shared<Variable_t>(vecVariable_.size(), num));
    }

    //5.
    resetValue(vecVariable_.begin() + startIndex, vecVariable_.end());
    return true;
}

void BaseSolver::resetValue(std::vector<std::shared_ptr<Variable_t>>::iterator si, std::vector<std::shared_ptr<Variable_t>>::iterator ei)
{
    for (auto it = si; it != ei; ++it)
    {
        resetVar(*it);
    }
}

void BaseSolver::addInter()
{
    //1.
    for (auto &var : vecVariable_)
    {
        var->num++;
    }

    //2.
    if (bestVar_ != nullptr)
    {
        bestVar_->num = 0;
    }
}

void BaseSolver::saveResult()
{
    //1.
    if (resFile_.empty())
    {
        return;
    }

    //2.
    std::ofstream fw(resFile_);
    if (!fw.is_open())
    {
        LogError("无法将结果写入文件:{}", resFile_);
        return;
    }

    //3.
    auto now  = std::chrono::system_clock::now();
    auto time = std::chrono::system_clock::to_time_t(now);
    fw  << std::setprecision(16);
    fw  << "求解器     :" << name_ << "\n"
        << "当前时间   :" << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S") << "\n"
        << "目标最小值 :" << condition_.currentError.load()   << "\n"
        << "总迭代次数 :" << condition_.limitIter  << "\n"
        << "当前最优解 :[ ";
    
    auto &x = bestVar_->best->x;
    if (x.size() < 6)
    {
        fw << x[0];
        for (Eigen::Index i = 1; i != x.size(); ++i)
        {
            fw << ", " << x[i];
        }
    }
    else
    {
        for (auto v : x)
        {
            fw << "\n" << v;
        }
    }
    fw << " ]\n\n historyY = [";
    for (auto v : vecHistoryY_)
    {
        fw << "\n" << v;
    }
    fw << " ]";

    //4.
    LogInfo("结果已经写入到文件:" + resFile_);
}

bool BaseSolver::searchLocal(std::shared_ptr<Variable_t> &var)
{
    //1.
    if (getRandUniform01() > 0.8)
    {
        if (searchForBestLocal(var, 1.0))
        {
            return true;
        }
    }

    //2.
    if (getRandUniform01() > 0.5)
    {
        if (searchForBestLocal(var, 0.1))
        {
            return true;
        }
    }

    //3.
    if (searchForBestLocal(var, 0.01))
    {
        return true;
    }

    //4.
    return false;
}

bool BaseSolver::searchForBestLocal(std::shared_ptr<Variable_t> &var, const value_t startWeight)
{
    constexpr value_t endWeight = 0.001;

    //1.
    value_t upY;
    value_t mul     = endWeight + (startWeight - endWeight) * (condition_.limitIter - condition_.currentInter) / condition_.limitIter;
    auto &x         = var->opt->x;
    auto &x0        = var->current->x;
    std::size_t num = x.size();
    
    //2.
    for (uint8_t k = 0; k != 64; ++k)
    {
        upY = var->current->y;
        for (auto &ptr : vecVariable_)
        {
            //2.1
            if (ptr == var)
            {
                continue;
            }

            //2.2
            if (condition_.stop.load())
            {
                return true;
            }

            //2.3
            auto &x1 = ptr->current->x;
            for (std::size_t i = 0; i != num; ++i)
            {
                x[i] = x0[i] + (getRandUniform01() - 0.5) * mul * (x0[i] - x1[i]);
            }

            //2.4
            normVar(x, x0);

            //2.5
            var->opt->y = fun_->calcFun(x);
            if (updateVariable(var, false))
            {
                if (var->best->y < condition_.limitError)
                {
                    bestVar_ = var;
                    return true;
                }
            }
        }

        if (var->current->y * 1.001 > upY)
        {
            return false;//陷入局部最优,直接返回
        }

        mul *= 0.9;
    }

    return false;
}

bool BaseSolver::searchByDiff(std::shared_ptr<Variable_t>& var, bool forceUpdate)
{
    //1.
    if (vecMax_.size() > 36)
    {
        return false;
    }

    //2.
    auto &x0 = var->current->x;
    calcDiff(x0, vecDiff_);

    //3.
    double_t mul = 8;
    auto &x = var->opt->x;
    const std::size_t num = x.size();
    for (uint8_t k = 0; k != 12; ++k)
    {
        for (std::size_t i = 0; i != num; ++i)
        {
            x[i] = x0[i] - mul * vecDiff_[i];
        }

        normVar(x, x0);
        var->opt->y = fun_->calcFun(x);
        if (var->opt->y < var->current->y)
        {
            updateVariable(var, false);
            return var->best->y < condition_.limitError;
        }

        mul /= 2;
    }

    //4.
    if (forceUpdate)
    {
        for (std::size_t i = 0; i != num; ++i)
        {
            x[i] = x0[i] - 0.5 * getRandUniform01() * vecDiff_[i];
        }

        normVar(x, x0);
        var->opt->y = fun_->calcFun(x);
        updateVariable(var, true);
        return var->best->y < condition_.limitError;
    }
    else
    {
        return false;
    }
}

void BaseSolver::calcDiff(const VectorXd_t &x, VectorXd_t &diff)
{
    constexpr value_t ConstEps1E9 = 1e-9;
    value_t x0, y1, y0, h, absx;
    const std::size_t num = x.size();
    VectorXd_t x1 = x;
    for (std::size_t i = 0; i != num; ++i)
    {
        //1.
        x0 = x[i];
        absx = std::fabs(x0);
        if (absx > 1.0)
        {
            h = absx * ConstEps1E9;
        }
        else
        {
            h = ConstEps1E9;
        }

        //2.
        x1[i] = x0 + h;
        normVar(x1, x);
        y1 = fun_->calcFun(x1);
        x1[i] = x0 - h;
        normVar(x1, x);
        y0 = fun_->calcFun(x1);

        diff[i] = (y1 - y0) / (2 * h);
        x1[i] = x0;
    }
}

bool BaseSolver::mixBest3(bool updateForce)
{
    value_t r1, r2;
    for (auto &var : vecVariable_)
    {
        //1.
        if (var == bestVar_)
        {
            continue;
        }

        //2.
        if (condition_.stop.load())
        {
            return true;
        }

        //3.
        auto &x  = var->opt->x;
        auto &x0 = var->current->x;
        auto &x1 = bestVar_->best->x;
        auto &x2 = vecVariable_[getRandIndex(vecVariable_.size())]->current->x;
        r1 = getRandUniform01() * 0.5;
        r2 = getRandUniform01() * 0.5;

        //4.
        //x = x0 + r1 * (x1 - x0) + r2 * (x2 - x0)
        //x = x0 * (1 - r1 - r2) + r1 * x1 + r2 * x2
        add3(x, 1 - r1 - r2, x0, r1, x1, r2, x2);
        normVar(x, x0);
        var->opt->y = fun_->calcFun(x);
        if (updateVariable(var, updateForce))
        {
            if (var->best->y < condition_.limitError)
            {
                bestVar_ = var;
                return true;
            }
        }
    }

    return false;
}

bool BaseSolver::mixBest4(bool updateForce)
{
    value_t r1, r2, r3;
    for (auto &var : vecVariable_)
    {
        //1.
        if (var == bestVar_)
        {
            continue;
        }

        //2.
        if (condition_.stop.load())
        {
            return true;
        }

        //3.
        auto &x  = var->opt->x;
        auto &x0 = var->current->x;
        auto &x1 = bestVar_->best->x;
        auto &x2 = vecVariable_[getRandIndex(vecVariable_.size())]->current->x;
        auto &x3 = vecVariable_[getRandIndex(vecVariable_.size())]->current->x;
        r1 = getRandUniform01() * 0.5;
        r2 = getRandUniform01() * 0.25;
        r3 = getRandUniform01() * 0.25;

        //4.
        //x = x0 + r1 * (x1 - x0) + r2 * (x2 - x0) + r3 * (x3 - x0)
        //x = x0 * (1 - r1 - r2 - r3) + r1 * x1 + r2 * x2 + r3 * x3
        add4(x, 1 - r1 - r2, x0, r1, x1, r2, x2, r3, x3);
        normVar(x, x0);
        var->opt->y = fun_->calcFun(x);
        if (updateVariable(var, updateForce))
        {
            if (var->best->y < condition_.limitError)
            {
                bestVar_ = var;
                return true;
            }
        }
    }

    return false;
}

void BaseSolver::shuffleVarIndex()
{
    //1.
    if (vecVarIndex_.size() != vecVariable_.size())
    {
        vecVarIndex_.resize(vecVariable_.size());
        for (std::size_t i = 0; i != vecVariable_.size(); ++i)
        {
            vecVarIndex_[i] = i;
        }
    }

    //2.
    std::random_device rd;
    std::mt19937 g(rd());
    std::shuffle(vecVarIndex_.begin(), vecVarIndex_.end(), g);
}

value_t BaseSolver::calcLevy()
{
	constexpr value_t sigma = 0.696574502557697 * 0.05;
	value_t u = getRandUniform01() * sigma;
	value_t v = std::pow(getRandNorm01(), 2.0 / 3);
	if (v < 1e-12)
	{
		v = 1e-12;
	}

	return u / v;
}

void BaseSolver::getNoUpdateVariable(std::vector<std::shared_ptr<Variable_t>> &outVar, uint32_t num) const
{
    outVar.clear();
    for (auto &var : vecVariable_)
    {
        if (var->num >= num)
        {
            outVar.push_back(var);
        }
    }
}

void BaseSolver::sortBestForVariable()
{
    std::sort(vecVariable_.begin(), vecVariable_.end(), [](const std::shared_ptr<Variable_t> &a, const std::shared_ptr<Variable_t> &b)-> bool
    {
        return a->best->y < b->best->y;
    });
}

bool BaseSolver::updateVariable(std::shared_ptr<Variable_t> &var, bool updateForce) const
{
    if (updateForce || var->current->y > var->opt->y)
    {
        //1.
        copyData(var->opt, var->current);

        //2.
        if (var->best->y > var->opt->y)
        {
            var->num = 0;
            copyData(var->opt, var->best);
        }

        //3.
        return true;
    }
    else
    {
        return false;
    }
}

void BaseSolver::add2(  VectorXd_t &x, 
                        value_t r1, const VectorXd_t &x1, 
                        value_t r2, const VectorXd_t &x2) const
{
    x = r1 * x1 + r2 * x2;
}

void BaseSolver::add3(  VectorXd_t &x,
                        value_t r1, const VectorXd_t &x1, 
                        value_t r2, const VectorXd_t &x2, 
                        value_t r3, const VectorXd_t &x3) const
{
    x = r1 * x1 + r2 * x2 + r3 * x3;
}

void BaseSolver::add4(  VectorXd_t &x,
                        value_t r1, const VectorXd_t &x1, 
                        value_t r2, const VectorXd_t &x2, 
                        value_t r3, const VectorXd_t &x3,
                        value_t r4, const VectorXd_t &x4) const
{
    x = r1 * x1 + r2 * x2 + r3 * x3 + r4 * x4;
}

void BaseSolver::add3Same(  VectorXd_t &x,
                            value_t r,
                            const VectorXd_t &x1, 
                            const VectorXd_t &x2, 
                            const VectorXd_t &x3) const
{
    x = x1 + r * (x3 -  x2);
}

void BaseSolver::add5Same(  VectorXd_t &x,
                            value_t r1,
                            value_t r2,
                            const VectorXd_t &x1, 
                            const VectorXd_t &x2, 
                            const VectorXd_t &x3,
                            const VectorXd_t &x4, 
                            const VectorXd_t &x5) const
{
    x = x1 + r1 * (x3 - x2) + r2 * (x5 - x4);
}

void BaseSolver::add7Same(  VectorXd_t &x,
                            value_t r1,
                            value_t r2,
                            value_t r3,
                            const VectorXd_t &x1, 
                            const VectorXd_t &x2, 
                            const VectorXd_t &x3,
                            const VectorXd_t &x4, 
                            const VectorXd_t &x5,
                            const VectorXd_t &x6, 
                            const VectorXd_t &x7) const
{
    x = x1 + r1 * (x3 - x2) + r2 * (x5 - x4) + r3 * (x7 - x6);
}

void BaseSolver::add3Rand(  VectorXd_t &x,
                            value_t r,
                            const VectorXd_t &x1, 
                            const VectorXd_t &x2, 
                            const VectorXd_t &x3)
{
    const Eigen::Index num = x.size();
    for (Eigen::Index i = 0; i != num; ++i)
    {
        x[i] = x1[i] + r * getRandUniform01() * (x3[i] - x2[i]);
    }
}

void BaseSolver::add5Rand(  VectorXd_t &x,
                            value_t r1,
                            value_t r2,
                            const VectorXd_t &x1, 
                            const VectorXd_t &x2, 
                            const VectorXd_t &x3,
                            const VectorXd_t &x4, 
                            const VectorXd_t &x5)
{
    const Eigen::Index num = x.size();
    for (Eigen::Index i = 0; i != num; ++i)
    {
        x[i] = x1[i] + r1 * getRandUniform01() * (x3[i] - x2[i]) + r2 * getRandUniform01() * (x5[i] - x4[i]);
    }
}

void BaseSolver::add7Rand(  VectorXd_t &x,
                            value_t r1,
                            value_t r2,
                            value_t r3,
                            const VectorXd_t &x1, 
                            const VectorXd_t &x2, 
                            const VectorXd_t &x3,
                            const VectorXd_t &x4, 
                            const VectorXd_t &x5,
                            const VectorXd_t &x6, 
                            const VectorXd_t &x7)
{
    const Eigen::Index num = x.size();
    for (Eigen::Index i = 0; i != num; ++i)
    {
        x[i] = x1[i] + r1 * getRandUniform01() * (x3[i] - x2[i]) + r2 * getRandUniform01() * (x5[i] - x4[i]) + r3 * getRandUniform01() * (x7[i] - x6[i]);
    }
}

bool BaseSolver::initSolver()
{
    //1.
    if (fun_ == nullptr)
    {
        LogError("没有设置最小化目标函数");
        return false;
    }

    //2.
    if (vecMax_.size() == 0)
    {
        LogError("没有设置变量求解范围");
        return false;
    }

    //3.
    vecDiff_.resize(vecMax_.size());
    return init();
}

void BaseSolver::updateBestVar()
{
    //1.
    bestVar_ = *std::min_element(vecVariable_.begin(), vecVariable_.end(), [](const std::shared_ptr<Variable_t> &a, const std::shared_ptr<Variable_t> &b)->bool
                {
                    return a->best->y < b->best->y;
                });

    //2.
    condition_.currentError.store(bestVar_->best->y);
}

void BaseSolver::normVar(VectorXd_t &x, const VectorXd_t &x0)
{
    //1.
    constexpr value_t ConstMul = 0.25;
    const std::size_t num = x.size();
    for (std::size_t i = 0; i != num; ++i)
    {
        if (x[i] < vecMin_[i])
        {
            x[i] = vecMin_[i] + ConstMul * (x0[i] - vecMin_[i]) * getRandUniform01();
        }
        else if(x[i] > vecMax_[i])
        {
            x[i] = vecMax_[i] + ConstMul * (x0[i] - vecMax_[i]) * getRandUniform01();
        }
    }

    //2.
    fun_->normVar(x);
}

value_t BaseSolver::getRandNorm01()
{
    const value_t r = randNorm01_(gen_);
    if (r < 0 || r > 1)
    {
        return randUniform01_(gen_);
    }
    else
    {
        return r;
    }
}

value_t BaseSolver::getRandUniform01()
{
    return randUniform01_(gen_);
}

std::size_t BaseSolver::getRandIndex(std::size_t num)
{
    const value_t v = randUniform01_(gen_) * (num - 0.001) - 1;
    return v < 0 ? 0 : static_cast<std::size_t>(v);
}

void BaseSolver::copyData(const std::shared_ptr<DataValue_t> &src, const std::shared_ptr<DataValue_t> &dst) const
{
    dst->y = src->y;
    std::copy(src->x.begin(), src->x.end(), dst->x.begin());
}

std::size_t BaseSolver::getRandInt(std::size_t startIndex, std::size_t endIndex)
{
    //1.
    value_t r = getRandUniform01() * (endIndex - startIndex) - 0.5;
    if (r < 0)
    {
        return startIndex;
    }

    //2.
    const std::size_t i = std::round(r) + startIndex;
    return i < endIndex ? i : endIndex - 1;
}

void BaseSolver::calcAvg(VectorXd_t &avg) const
{
    //1.
    std::fill(avg.begin(), avg.end(), 0);

    //2.
    for (auto &var : vecVariable_)
    {
        std::transform(avg.begin(), avg.end(), var->current->x.begin(), avg.begin(), std::plus<value_t>());
    }

    //3.
    for (auto &v : avg)
    {
        v /= vecVariable_.size();
    }
}

void BaseSolver::resetVar(std::shared_ptr<Variable_t> &var)
{
    const std::size_t num = vecMax_.size();
    auto &x0  = var->best->x;
    auto &x1  = var->current->x;
    for (std::size_t i = 0; i != num; ++i)
    {
        x0[i] = (vecMin_[i] + vecMax_[i]) / 2 + (getRandNorm01() - 0.5) * (vecMax_[i] - vecMin_[i]);
        x1[i] = x0[i];
    }

    var->best->y = fun_->calcFun(x0);
    var->current->y = var->best->y;
}

}